﻿using System;
using System.Windows.Forms;
using agsXMPP;
using agsXMPP.protocol.client;
using AlphaMobileControls;
using Lapd.Common;
using Lapd.Common.Helpers;
using Lapd.Pd.Resources;
using Microsoft.WindowsMobile.Samples.Location;

namespace Lapd.Pd
{
    public partial class Main : AlphaForm
    {
        #region Members

        private XmppClientConnection _xmppClientConnection;
        private GpsPosition _currentPosition;
        private Gps _gps;
        private IGpsHelper _gpsHelper;

        /// <summary>
        /// To avoid multilpe lost alarms been sent
        /// </summary>
        private bool _lostAlarmSent;

        /// <summary>
        /// Is true when the login, listen and the other init commands have been completed successfully
        /// </summary>
        private bool _formReady;

        #endregion

        #region Constructors

        public Main()
        {
            InitializeComponent();

            // Initialize XMPP connection
            _xmppClientConnection = InitializeXmppClientConnection();

            // Initialize alpha controls ---------------------------------------------
            BellPicture.Image = AlphaImage.CreateFromResource("Lapd.Pd.Resources.008_Reminder_48x48_72.png");

            // Initialize helpers
            _gpsHelper = new GpsHelper();

            // Initialize GPS manager
            _gps = new Gps();
            _gps.LocationChanged += new LocationChangedEventHandler(GpsManagerLocationChanged);

            // Open GPS Manager
            if (!_gps.Opened)
            {
                _gps.Open();
            }

            // 1.- Login (async call)
            ServiceDdsHelper.Login(Session.Server, Session.UserName, Session.Domain, Session.Password, ref _xmppClientConnection);
        }

        #endregion

        #region Error events

        private void XmppCon_OnStreamError(object sender, agsXMPP.Xml.Dom.Element e)
        {
#if DEBUG
            StatusLabel.Text = Messages.Error_Stream;
#else
            StatusLabel.Text = Messages.Error_Generic;
#endif
        }

        private void XmppCon_OnSocketError(object sender, Exception ex)
        {
#if DEBUG
            StatusLabel.Text = Messages.Error_Socket;
#else
            StatusLabel.Text = Messages.Error_Generic;
#endif
        }

        #endregion

        #region Xmpp events

        private void XmppCon_OnLogin(object sender)
        {
            if (InvokeRequired)
            {
                // Windows Forms are not Thread Safe, we need to invoke this :(
                // We're not in the UI thread, so we need to call BeginInvoke				
                BeginInvoke(new ObjectHandler(XmppCon_OnLogin), new object[] { sender });
                return;
            }

            ProcessOnLogin();

        }

        void XmppCon_OnMessage(object sender, Message msg)
        {
            if (InvokeRequired)
            {
                // Windows Forms are not Thread Safe, we need to invoke this :(
                // We're not in the UI thread, so we need to call BeginInvoke				
                BeginInvoke(new MessageHandler(XmppCon_OnMessage), new object[] { sender, msg });
                return;
            }

            // Get instance name from the XML message
            string instanceName = ServiceDdsHelper.GetInstanceName(msg);

            switch (instanceName)
            {
                case ServiceDdsConstants.WARNING_REQUEST_TOPIC_INSTANCE_NAME:

                    ProcessWarningRequest();

                    break;
                case ServiceDdsConstants.LOCATION_REQUEST_TOPIC_INSTANCE_NAME:

                    ProcessLocationRequest();

                    break;
                default:

                    break;
            }

        }

        #endregion

        #region Gps events

        protected void GpsManagerLocationChanged(object sender, LocationChangedEventArgs args)
        {
            _currentPosition = args.Position;

            if (_formReady
                && _gps.Opened 
                && _currentPosition != null 
                && _currentPosition.LatitudeValid 
                && _currentPosition.LongitudeValid
                && _gpsHelper.OutOfPerimeter(_currentPosition)
                && !_lostAlarmSent)
            {
                // Send localisation alarm
                // Write on topic
                IQ iq = ServiceDdsHelper.WriteOnTopic(
                    ServiceDdsConstants.LOCATION_ALARM_TOPIC_INSTANCE_NAME,
                    ref _xmppClientConnection,
                    long.Parse(Session.UserId),
                    _currentPosition.Latitude,
                    _currentPosition.Longitude);

                // Retry sending the alarm until response iq != null
                if (iq != null)
                {
                    _lostAlarmSent = true;
                }
            }

        }

        #endregion

        #region UI events

        private void BellButton_Click(object sender, EventArgs e)
        {
            // Send help alarm
            IQ iq = ServiceDdsHelper.WriteOnTopic(
                ServiceDdsConstants.ALARM_TOPIC_INSTANCE_NAME,
                ref _xmppClientConnection,
                long.Parse(Session.UserId),
                ServiceDdsConstants.ALARM_TOPIC_HELP_TYPE);

            if (iq == null)
            {
                StatusLabel.Text = Messages.AlarmHelp_SendingError;
            }
            else
            {
                StatusLabel.Text = Messages.AlarmHelp_SentOk;
            }
        }

        private void ExitMenuItem_Click(object sender, EventArgs e)
        {
            Close();
        }

        #endregion

        #region Private methods

        private XmppClientConnection InitializeXmppClientConnection()
        {
            XmppClientConnection xmppClientConnection = new XmppClientConnection();

            xmppClientConnection.OnLogin += new ObjectHandler(XmppCon_OnLogin);
            xmppClientConnection.OnSocketError += new ErrorHandler(XmppCon_OnSocketError);
            xmppClientConnection.OnStreamError += new XmppElementHandler(XmppCon_OnStreamError);
            xmppClientConnection.OnMessage += new MessageHandler(XmppCon_OnMessage);

            return xmppClientConnection;
        }

        private void EnableForm()
        {
            stbMain.Text = Messages.Status_Connected;
            BellButton.Enabled = true;
            _formReady = true;
        }

        private void ProcessWarningRequest()
        {
            IQ iq;

            // Send warning response
            if (MessageBox.Show(Messages.WarningOk_Question, Messages.WarningOk_Title, MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) == System.Windows.Forms.DialogResult.Yes)
            {
                iq = ServiceDdsHelper.WriteOnTopic(
                    ServiceDdsConstants.WARNING_RESPONSE_TOPIC_INSTANCE_NAME,
                    ref _xmppClientConnection,
                    long.Parse(Session.UserId),
                    ServiceDdsConstants.WARNING_RESPONSE_TOPIC_OK);
            }
            else
            {
                iq = ServiceDdsHelper.WriteOnTopic(
                    ServiceDdsConstants.WARNING_RESPONSE_TOPIC_INSTANCE_NAME,
                    ref _xmppClientConnection,
                    long.Parse(Session.UserId),
                    ServiceDdsConstants.WARNING_RESPONSE_TOPIC_KO);
            }

            // Error handling
            if (iq == null)
            {
                StatusLabel.Text = Messages.WarningOk_SendingAnswerError;
            }
            else
            {
                StatusLabel.Text = Messages.WarningOk_SentOk;
            }
        }

        private void ProcessLocationRequest()
        {
            if (_gps.Opened
                && _currentPosition != null
                && _currentPosition.LatitudeValid
                && _currentPosition.LongitudeValid)
            {
                // Send location response
                ServiceDdsHelper.WriteOnTopic(
                            ServiceDdsConstants.LOCATION_RESPONSE_TOPIC_INSTANCE_NAME,
                            ref _xmppClientConnection,
                            long.Parse(Session.UserId),
                            _currentPosition.Latitude,
                            _currentPosition.Longitude);    
            }
        }

        private void ProcessOnLogin()
        {
            try
            {
                ServiceDdsHelper.InitializeServiceDDS(ref _xmppClientConnection);
                EnableForm();
            }
            catch (Exception)
            {
                StatusLabel.Text = Messages.Error_Generic;
            }
        }

        #endregion

    }
}